<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel=stylesheet type="text/css" href="bleu.css">

<title>iBLEU: Interactive BLEU Scoring</title>
<script src="js/bleu.js" type="text/javascript"></script>
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jquery.flot.js" type="text/javascript"></script>
<script src="js/utils.js" type="text/javascript"></script>
<script src="js/lcs.js" type="text/javascript"></script>
<script src="js/highcharts.js" type="text/javascript"></script>
<script src="js/gray.js" type="text/javascript"></script>

</head>

<body>
<br/>
<div align="center" id="title" style="font-size: 28px;">Interactive Bleu Scorer</div>
<br/>

<div align="center" id="formContainer">
<form id="fileForm" name="fileForm">
  <p id="srcFileStuff">
  <span class="fileLabel">Step 0: Pick source file (Optional)</span><br/><br/>
  <!-- <span style="font-size: 14px; line-height: 160%">[If you want Google Translate integration]</span> -->
  <input type="file" class="filepicker" name="srcFile" id="srcFile" size="60">
  </p>
  <p id="tstFileStuff">
  <span class="fileLabel">Step 1: Pick hypothesis file</span><br/><br/>
  <input type="file" class="filepicker" name="tstFile" id="tstFile" size="60"><br/>
  <a id="secondHypLink" href="#" style="font-size:12px; display:none;">Compare to another system?</a>
  <div id="secondHypDiv" name="secondHypDiv" style="display: none;">
    <span class="fileLabel">Pick second hypothesis file</span><br/><br/>
    <input type="file" class="filepicker" name="tstFile2" id="tstFile2" size="60"><br/>
  </div>
  </p>
  <p id="refFileStuff">
  <span class="fileLabel">Step 2: Pick reference file</span><br/><br/>
  <input type="file" class="filepicker" name="refFile" id="refFile" size="60">
  </p>
  <br/>
  <table border="0">
    <tr>
      <td align="center">
        <input type="checkbox" value="cased" name="caseCheckBox" id="caseCheckBox"/> Preserve case information
        &nbsp;&nbsp;&nbsp;&nbsp;
        <input type="checkbox" value="tokenized" name="tokenizeCheckBox" id="tokenizeCheckBox"/> Do not tokenize
      </td></tr>
      <tr><td>&nbsp;</td></tr>
      <tr><td>Compare to:
      <input type="radio" name="comparisonEngine" value="Google" id="comparisonEngine1" /> Google Translate
      <input type="radio" name="comparisonEngine" value="Bing" id="comparisonEngine2"/> Bing Translator
      <input type="radio" name="comparisonEngine" value="none" id="comparisonEngine3" /> None</td>
    </tr>
  </table>
  <br/>
  <input type="button" value="Score" name="scoreButton" id="scoreButton"/>
</form>
<div align="center" id="scoreSpinnerDiv"></div>
<div class="hider">
    <a id="formHider" class="jslink" href="#">Hide Form</a>
</div>
</div><br/>
<div align="center" id="bleuDetailContainer">
    <div align="center" id="bleuScoreDiv">&nbsp;</div><br/>
    <div align="center" id="bleuTableDiv">&nbsp;</div><br/>
</div>
<br/>
<div align="center" id="bleuDocPlotsContainer"></div>
<br/>
<div align="center" id="bleuSegPlotContainer">
    <div align="center" id="bleuSegPlot" style="width:700px; height:300px"></div>
</div>
<br/>
<div align="center" id="segDetailContainer"></div>
<br/>
</body>
<script type="application/javascript;version=1.8">
var tstSets = [];
var refSets = [];
var srcSets = [];
var maxN = 4;
var smoothed = true;
var scontainer;
var scontainer2;
var allDocPlots = [];
var segmentScoreTuples = {};
var docidpat = /DocID: (.*) \((.*)\)/;
var docidpat2 = /Segment (.*), Document "(.*)"/;

// Create a hash that will give us the two letter code for any language
var languageNameHash = new Array();
languageNameHash['French'] = 'fr';
languageNameHash['Chinese'] = 'zh';
languageNameHash['German'] = 'de';
languageNameHash['Spanish'] = 'es';
languageNameHash['Arabic'] = 'ar';
languageNameHash['Czech'] = 'cz';
languageNameHash['Dutch'] = 'nl';
languageNameHash['Danish'] = 'da';
languageNameHash['Hungarian'] = 'hu';
languageNameHash['English'] = 'en';

// If you want the tool to remember your Google Translate API key
// across sesions, please save it here
var google_translate_api_key = "";

// If you want the tool to remember your Microsoft Translator API key
// across sessions, please save it here
var bing_translate_api_key = "";

// Show the given bleu score in the appropriate place
function showScore(score, prec, brevity, sysid, srclang, numRefSets) {
  var elt = document.getElementById('bleuScoreDiv');
    var scorehtml = "<span style=\"font-size: 40px;\">" + (score*100).toFixed(2) + "</span><br/>" +
        prec.toFixed(4) + " * " + brevity.toFixed(4) + "<br/>" +
        "<span style=\"font-size:12px;\">";
    if (srclang != undefined) {
        scorehtml += "[Source Language: " + srclang + "]<br/>";
    }
    scorehtml += "[System: " + sysid + "]<br/>[" + numRefSets + " reference(s)]</span>";
    elt.innerHTML = scorehtml;
}

function lcsColorize(sentence, indices_to_color, color) {
    var colorhtml = '';
    var words = sentence.split(' ');
    for (var i=0; i<words.length; i++) {
        if (indices_to_color.indexOf(i) != -1) {
            colorhtml += words[i] + ' ';
        }
        else {
            colorhtml += '<span style="color: ' + color + '; font-weight: bold;">' + words[i] + '</span> ';
        }
  }
  return colorhtml;
}

// Show two BLEU scores side by side when we are comparing two systems
function showSideBySideScores(scores, precisions, brevities, sysids, srclang, numRefSets) {
    var elt = document.getElementById('bleuScoreDiv');
    var tr1 = "<tr><td style=\"font-size: 40px; text-align: center;\">" +  (scores[0]*100).toFixed(2) + "</td>";
    tr1 += "<td>&nbsp;&nbsp;&nbsp;vs&nbsp;&nbsp;&nbsp;</td>";
    tr1 += "<td style=\"font-size: 40px; text-align: center;\">" +  (scores[1]*100).toFixed(2) + "</td></tr>";
    var tr2 = "<tr><td style=\"text-align: center;\">" + precisions[0].toFixed(4) + " * " + brevities[0].toFixed(4) + "</td>";
    tr2 += "<td></td>";
    tr2 += "<td style=\"text-align: center;\">" + precisions[1].toFixed(4) + " * " + brevities[1].toFixed(4) + "</td></tr>";
    var tr3 = "<tr><td style=\"font-size: 12px; text-align: center;\">" + "[System: " + sysids[0] + "]</td>";
    tr3 += "<td></td>";
    tr3 += "<td style=\"font-size: 12px; text-align: center;\">" + "[System: " + sysids[1] + "]</td></tr>";
    trblank = "<tr><td colspan=\"3\">&nbsp;</td></tr>";
    tr4 = "<tr><td colspan=\"3\" style=\"text-align: center;\">";
    if (srclang != undefined) {
        tr4 += "[Source Language: " + srclang + "]<br/>";
    }
    tr4 += "[" + numRefSets + " reference(s)]</tr></td>";
    elt.innerHTML = "<table>" + tr1 + tr2 + tr3 + trblank + tr4 + "</table>";
}


// Show the details (individual and cumulative) precisions in a table
function showTable(individualNgramScores, cumulativeNgramScores) {
    var elt = document.getElementById('bleuTableDiv');
    elt.innerHTML = "<span style=\"font-size:12px;\">Breakdown of scores (<a href=\"\" class=\"jslink\" id=\"tableHider\">Show</a>)</span><br/>" +
                    "<table id=\"bleuTable\" border=1>" +
                     "<tr align=\"center\">" +
                       "<th>Type</th>" +
                       "<th>1-gram</th>" +
                       "<th>2-gram</th>" +
                       "<th>3-gram</th>" +
                       "<th>4-gram</th>" +
                     "</tr>" +
                 "<tr>" +
                       "<td>Individual</td>" +
                       "<td>" + individualNgramScores[1].toFixed(4) + "</td>" +
                       "<td>" + individualNgramScores[2].toFixed(4) + "</td>" +
                       "<td>" + individualNgramScores[3].toFixed(4) + "</td>" +
                       "<td>" + individualNgramScores[4].toFixed(4) + "</td>" +
                     "</tr>" +
                      "<tr>" +
                       "<td>Cumulative</td>" +
                       "<td>" + cumulativeNgramScores[1].toFixed(4) + "</td>" +
                       "<td>" + cumulativeNgramScores[2].toFixed(4) + "</td>" +
                       "<td>" + cumulativeNgramScores[3].toFixed(4) + "</td>" +
                       "<td>" + cumulativeNgramScores[4].toFixed(4) + "</td>" +
                       "</tr>" +
                       "</table>";
}

function showSegDetails(event) {

  var segnum = event.point.x;
  var docid = this.name.match(docidpat)[1];
  var bleu = event.point.y.toFixed(2);
  var lengths = [tstSets[0].documents[docid][segnum].split(" ").length];

  // Compute average reference length
  var reflens = refSets.map(function(rset) { return rset.documents[docid][segnum].split(" ").length; });
  lengths = lengths.concat(reflens);
  var avgreflen = reflens.reduce(function(a,b) { return a + b; })/reflens.length;

  // Compute the length ratio of the segment length to the average reference length
  var lenratio = lengths[0]/avgreflen;
  $('#segDetailContainer').show();
  var elt = document.getElementById('segDetailContainer');
  var reflens = lengths.slice(1);

  // Compute the longest common subsequence (LCS) between the appropriate
  // items: when there is a single system, then between the hyp and the ref(s)
  // and when there are two systems, then between the the hyps
  if (tstSets[1] != undefined) {
    var lcslist;
    var tokhyp1 = $('#tokenizeCheckBox').attr('checked') ? tstSets[0].untokenizedDocuments[docid][segnum] : tstSets[0].documents[docid][segnum];
    var tokhyp2 = $('#tokenizeCheckBox').attr('checked') ? tstSets[1].untokenizedDocuments[docid][segnum] : tstSets[1].documents[docid][segnum];
    lcslist = lcs(tokhyp1.split(' '), tokhyp2.split(' '));
  }
  else {
    var hypLCSList = [];
    var refLCSLists = [];
    // var tokhyp = tstSets[0].documents[docid][segnum];
    var tokhyp = $('#tokenizeCheckBox').attr('checked') ? tstSets[0].untokenizedDocuments[docid][segnum] : tstSets[0].documents[docid][segnum];
    for (var i=0; i<refSets.length; i++) {
      var tokref = $('#tokenizeCheckBox').attr('checked') ? refSets[i].untokenizedDocuments[docid][segnum] : refSets[i].documents[docid][segnum];
      var lcslist = lcs(tokhyp.split(' '), tokref.split(' '));
      hypLCSList.push.apply(hypLCSList, lcslist.xindices);
      refLCSLists.push(lcslist.yindices);
    }
  }

  // show the header for the table
    if (tstSets[1] != undefined) {
        var tablehtml = '<table border="1" style="margin: 0px auto; width: 700px;">' +
                        '<tr>' +
                            '<td align="center" id="segDetailHeader" width="20%">ID</td>' +
                            '<td align="left" id="segDetailID">Segment ' + (segnum+1) + ', Document "' + docid + '"' +
                            ' [&Delta;<sub>BLEU</sub>=' + bleu + ']</td>' +
                        '</tr>';
    }
    else {
        var tablehtml = '<table border="1" style="margin: 0px auto; width: 700px;">' +
                        '<tr>' +
                            '<td align="center" id="segDetailHeader" width="20%">ID</td>' +
                            '<td align="left" id="segDetailID">Segment ' + (segnum+1) + ', Document "' + docid + '"' +
                            ' [' + bleu + ' BLEU, '+ lenratio.toFixed(3) + ' Length Ratio]</td>' +
                        '</tr>';
    }

    // Add the source sentence, if availble
    if (srcSets.length > 0) {
        var src = srcSets[0].documents[docid][segnum];
        tablehtml += '<tr>' +
                     '<td align="center" id="segDetailHeader">Source</td>' +
                     '<td id="segDetailSrc">' + src + '</td>' +
                     '</tr>';
    }

    // Add all the references
    for(var i=0; i < refSets.length; i++) {
      if (tstSets[1] != undefined) {
        var ref = $('#tokenizeCheckBox').attr('checked') ? refSets[i].untokenizedDocuments[docid][segnum] : refSets[i].documents[docid][segnum];
        ref = $('#caseCheckBox').attr('checked') ? ref : ref.toLowerCase();
        tablehtml += '<tr>' +
                   '<td align="center" id="segDetailHeader">Reference<br/>(' + refSets[i].refid + ')</td>' +
                   '<td id="segDetailRef' + i + '">' + ref + '</td>' +
                     '</tr>';
      }
      else {
        var tokref = $('#tokenizeCheckBox').attr('checked') ? refSets[i].untokenizedDocuments[docid][segnum] : refSets[i].documents[docid][segnum];
        tokref = $('#caseCheckBox').attr('checked') ? tokref : tokref.toLowerCase();
        ref_html = lcsColorize(tokref, refLCSLists[i], '#CC3333');
        tablehtml += '<tr>' +
                   '<td align="center" id="segDetailHeader">Reference<br/>(' + refSets[i].refid + ')</td>' +
                   '<td id="segDetailRef' + i + '">' + ref_html + '</td>' +
                     '</tr>';
      }
    }

    // Add the hypothesis or hypotheses as the case may be
    if (tstSets[1] != undefined) {
        tokhyp1 = $('#caseCheckBox').attr('checked') ? tokhyp1 : tokhyp1.toLowerCase();
        hyp1_html = lcsColorize(tokhyp1, lcslist.xindices, 'blue');
        tablehtml += '<tr>' +
                 '<td align="center" id="segDetailHeader">Hypothesis<br/>(' + tstSets[0].sysid + ')</td>' +
                 '<td id="segDetailHyp">' + hyp1_html + '<span style="font-size: 11px;"> [' + segmentScoreTuples[docid][segnum][0].toFixed(2) + ']</span></td>' +
                 '</tr>';

        // hyp = tstSets[1].untokenizedDocuments[docid][segnum];
        tokhyp2 = $('#caseCheckBox').attr('checked') ? tokhyp2 : tokhyp2.toLowerCase();
        hyp2_html = lcsColorize(tokhyp2, lcslist.yindices, 'blue');
        tablehtml += '<tr>' +
                 '<td align="center" id="segDetailHeader">Hypothesis<br/>(' + tstSets[1].sysid + ')</td>' +
                 '<td id="segDetailHyp">' + hyp2_html + '<span style="font-size: 11px;"> [' + segmentScoreTuples[docid][segnum][1].toFixed(2) + ']</span></td>' +
                 '</tr>';
    }
    else {
        var hyp = $('#tokenizeCheckBox').attr('checked') ? tstSets[0].untokenizedDocuments[docid][segnum] : tstSets[0].documents[docid][segnum];
        tokhyp = $('#caseCheckBox').attr('checked') ? tokhyp : tokhyp.toLowerCase();
        hyp_html = lcsColorize(tokhyp, hypLCSList, '#CC3333');
        tablehtml += '<tr>' +
             '<td align="center" id="segDetailHeader">Hypothesis<br/>(' + tstSets[0].sysid + ')</td>' +
             '<td id="segDetailHyp">' + hyp_html + '</td>' +
             '</tr>';

    }

    // Show a google/bing translate link if there is a source file
    if (srcSets.length > 0) {
        var engineName = $('input[name=comparisonEngine]:checked').val();
        if (engineName != "none") {
            tablehtml += '<tr id="segDetailEngine"><td style="text-align:center; font-size: 14px;" colspan=2><a href="#" class="jslink" id="engineTranslate">What does ' + engineName + ' say?</a></td></tr>';
        }
    }

    tablehtml += '</table>';
    elt.innerHTML = tablehtml;

  $('html, body').animate({
    scrollTop: $("#segDetailContainer").offset().top
  }, 1000);
}


function googleTranslate(text) {
    var newScript = document.createElement('script');
    var source = "https://www.googleapis.com/language/translate/v2?key=" + window.google_translate_api_key + "&target=en&callback=showGoogleTranslation&q=" + text;
    newScript.src = source;
    document.getElementsByTagName('head')[0].appendChild(newScript);
    document.getElementsByTagName('head')[0].removeChild(newScript);
    newScript = null;
}

function bingTranslate(srctext, srclang) {

    // if we don't know the language then try to automatically detect it
    if (srclang == "unknown") {
        var p = {};
        p.appid = window.bing_translate_api_key;
        p.text = srctext;
        srclang = $.ajax({
            url: 'http://api.microsofttranslator.com/V2/Ajax.svc/Detect',
            data: p,
            type: 'GET',
            cache: true,
            dataType: 'jsonp',
            jsonp: 'oncomplete',
            success: function(data, status) {
                var newScript = document.createElement('script');
                var source = "http://api.microsofttranslator.com/V2/Ajax.svc/Translate?oncomplete=showBingTranslation&contentType=text/html&appId=" + window.bing_translate_api_key + "&from=" + data + "&to=en&text=" + p.text;
                // alert(source);
                newScript.src = source;
                document.getElementsByTagName('head')[0].appendChild(newScript);
                document.getElementsByTagName('head')[0].removeChild(newScript);
                newScript = null;
            }
        });
    }
    else {
        var newScript = document.createElement('script');
        var source = "http://api.microsofttranslator.com/V2/Ajax.svc/Translate?oncomplete=showBingTranslation&contentType=text/html&appId=" + window.bing_translate_api_key + "&from=" + languageNameHash[srclang] + "&to=en&text=" + srctext;
        newScript.src = source;
        document.getElementsByTagName('head')[0].appendChild(newScript);
        document.getElementsByTagName('head')[0].removeChild(newScript);
        newScript = null;
    }
}

function showBingTranslation(response) {
    var translation = response;
    var finalTranslation = $('#caseCheckBox').attr('checked') ? translation : translation.toLowerCase();
    var tdhtml = '<td width="20%" id="segDetailHeader">Bing</td>' +
                  '<td id="segDetailEngineTrans">' + finalTranslation + '</td>';
    $('tr#segDetailEngine').html(tdhtml);
}

function showGoogleTranslation(response) {
    var translation = response.data.translations[0].translatedText;
    var finalTranslation = $('#caseCheckBox').attr('checked') ? translation : translation.toLowerCase();
    var tdhtml = '<td width="20%" id="segDetailHeader">Google</td>' +
                  '<td id="segDetailEngineTrans">' + finalTranslation + '</td>';
    $('tr#segDetailEngine').html(tdhtml);
}

function makeColumnChart(plotdiv, yscores, xticks, label, smallOrBig, ymin, ymax) {
    var chart;
    var showToolTips;
    var pointwidth;
    var showLegend;
    var showAnimation;
    var clickCallBack;
    var showXTicks;
    var YTickInterval;
    var XTickWidth;
    var pointClickCallback;
    var pointCursor;

    if (smallOrBig == "small") {
        showToolTips = false;
        showLegend = false;
        showAnimation = false;
        pointwidth = 2;
        clickCallback = { click: showLargerPlot };
        showXTicks = false;
        YTickInterval = 0.5;
        XTickWidth = 0;
        pointClickCallback = { legendItemClick : function(event) { return false; }, };
        pointCursor = 'auto';
    }
    else {
        showToolTips = true;
        showLegend = true;
        showAnimation = true;
        pointwidth = null;
        clickCallback = { };
        showXTicks = true;
        YTickInterval = 0.2;
        XTickWidth = null;
        pointClickCallback = { legendItemClick : function(event) { return false; }, click : showSegDetails};
        pointCursor = 'pointer';
    }

    if (yscores.length > 35) {
      showXTicks = false;
    }

    chart = new Highcharts.Chart({
        chart: {
            renderTo: plotdiv,
            defaultSeriesType: 'column',
            animation: showAnimation,
            borderRadius: 5,
            events: clickCallback
        },
        title: {
            text: ''
        },
        xAxis: {
            tickWidth: XTickWidth,
            categories: xticks,
            labels: {
                enabled: showXTicks
            }
        },
        yAxis: {
            min: ymin,
            max: ymax,
            tickInterval: YTickInterval,
            title: {
                text: ''
            }
        },
        tooltip: {
            enabled: showToolTips,
            formatter: function() {
                return this.y.toFixed(2);
            }
        },
        legend: {
            // align: 'right',
            // verticalAlign: 'top',
            // x: 0,
            // y: 10,
            // floating: true,
            enabled: showLegend
        },
        plotOptions: {
            column: {
                cursor : pointCursor,
                pointWidth: pointwidth,
                borderWidth: 0,
                enableMouseTracking: showToolTips,
                events: pointClickCallback
            }
        },
        series: [{
            animation: showAnimation,
            shadow: false,
            name: label,
            data: yscores,
        }],
        credits: {
            enabled: false
        }
    });
    return chart;
}


// Create the plot data for all the documents
function createDocPlotsData(documentScores, segmentScores) {
    var alldScores = [];
    var alldTicks = [];
    var d = [];
    var docScoreLabels = [];
    var docIdNumHash = {};

    // Create the labels for each plot (the document scores)
    var i = 0;
    for (docid in documentScores) {
        docScoreLabels[i] = [docid, documentScores[docid].toFixed(2)];
        docIdNumHash[docid] = i;
        alldScores[i] = [];
        i += 1;
    }

    // Create the data for segment scores for each document plot
    for (var j=0; j<segmentScores.length; j++) {
        var so = segmentScores[j];
        alldScores[docIdNumHash[so.docid]].push(so.score);
    }

    // Now go over each array in alld and add the x axis ticks
    for (var k=0; k<alldScores.length; k++) {
        alldTicks[k] = [];
        for (var l=0; l<alldScores[k].length; l++) {
            alldTicks[k].push(l);
        }
    }

    // return everything
    return [alldScores, alldTicks, docScoreLabels];
}


// Create the plot data for all the documents
function createDocPlotsDataForComparison(documentScores1, segmentScores1, documentScores2, segmentScores2) {

  var documentScoreDiffs = {};
  var segmentScoreDiffs = [];
  var alldScores = [];
  var alldTicks = [];
  var docScoreLabels = [];
  var docIdNumHash = {};

    // Compute the differences in the document scores ...
    for (docid in documentScores1) {
        documentScoreDiffs[docid] = documentScores1[docid] - documentScores2[docid];
    }

    // ... and the segment scores
  for (var j=0; j<segmentScores1.length; j++) {
    var sd = {};
    var score1 = segmentScores1[j].score;
    var score2 = segmentScores2[j].score;
    var diff = score1 - score2;
    sd.diff = diff;
    sd.docid = segmentScores1[j].docid;
    sd.segnum = segmentScores1[j].segnum;
    segmentScoreDiffs.push(sd);
    if (!segmentScoreTuples[sd.docid]) {
        segmentScoreTuples[sd.docid] = []
    }
    segmentScoreTuples[sd.docid].push([score1, score2]);
  }

    // Sort the document score diffs by magnitude so that the document with the largest
    // BLEU delta (negative or positive) shows up first
    var tuples = [];
    var sortedDocIDs = [];

    for (var docid in documentScoreDiffs) tuples.push([docid, documentScoreDiffs[docid]]);

    tuples.sort(function(a, b) {
        a = a[1];
        b = b[1];
        return Math.abs(a) < Math.abs(b) ? 1 : (Math.abs(a) > Math.abs(b) ? -1 : 0);
    });

    for (var i=0; i<tuples.length; i++) {
        sortedDocIDs.push(tuples[i][0]);
    }

    // Create the labels for each plot (the document score differences)
    var i = 0;
    var label;
    // for (docid in documentScoreDiffs) {
    for (var j=0; j<sortedDocIDs.length; j++) {
        var docid = sortedDocIDs[j];
        var diff = documentScoreDiffs[docid];
        label = diff < 0 ? diff.toFixed(2) : '+' + diff.toFixed(2);
        docScoreLabels[i] = [docid, label];
        docIdNumHash[docid] = i;
        alldScores[i] = [];
        i += 1;
    }

    // Create the data for segment scores for each document plot
    for (var j=0; j<segmentScoreDiffs.length; j++) {
        var sd = segmentScoreDiffs[j];
        alldScores[docIdNumHash[sd.docid]].push(sd.diff);
    }

    // Now go over each array in alld and add the x axis ticks
    for (var k=0; k<alldScores.length; k++) {
        alldTicks[k] = [];
        for (var l=0; l<alldScores[k].length; l++) {
            alldTicks[k].push(l);
        }
    }

    // return everything
    return [alldScores, alldTicks, docScoreLabels];
}

function showLargerPlot(event) {

    var plotNumber = $(this.container).parent().attr('id').slice(-3);

    // get the data from the smaller plot
    var series = this.series[0];
    var data = series.data;
    var label = series.name;
    var yscores = [];
    var xticks = [];

    for (var i=0; i<data.length; i++) {
        yscores.push(data[i].y);
        xticks.push(data[i].x+1);
    }

    var ymin = series.yAxis.getExtremes().min;
    var ymax = series.yAxis.getExtremes().max;

    $('#bleuSegPlotContainer').show();
    var largerPlot = makeColumnChart('bleuSegPlot', yscores, xticks, label, "big", ymin, ymax);

    // clear any segment details
    $('#segDetailContainer').html("");
    $('html, body').animate({
        scrollTop: $("#bleuSegPlotContainer").offset().top
    }, 1000);

}

$(document).ready(function() {

    // Clear the file fields on load
    $(':input','#fileForm')
      .not(':button')
      .not(':radio')
      .val('');

    // Clear the checkboxes
    $('#caseCheckBox').attr('checked', false);
    $('#tokenizeCheckBox').attr('checked', false);

    // Set the radio buttons to 'none' by default and disable the other two
    $('input[name=comparisonEngine]').filter('#comparisonEngine1').attr('disabled', 'disabled')
    $('input[name=comparisonEngine]').filter('#comparisonEngine2').attr('disabled', 'disabled')
    $('input[name=comparisonEngine]').filter('#comparisonEngine3').attr('checked', 'checked')

    // Hide the bleu details
    $('#bleuScoreDiv').html("");
    $('#bleuTableDiv').html("");
    $('bleuDetailContainer').hide();
    //$('#bleuDetailContainer').css('border','none');

    // Hide the bleu plots
    $('#bleuSegPlot').html("");
    $('#bleuDocPlotsContainer').hide();
    $('#bleuSegPlotContainer').hide();

    // Clear any stray tooltips
    // $("#tooltip").remove();

    // Hide any segment details
    $('#segDetailContainer').html("");

    // Initialize the score containers
    scontainer = null;
    scontainer2 = null;

    // Process the source xml or plaintext file
    // We make the decision based on the extension right now which is a bit hacky
    $('#srcFile').change(function (e) {
        srcSets = [];
        var srcfile = e.target.files[0];
        var reader = new FileReader();
        reader.onload = function() {
            var extension = srcfile.name.split('.').pop();

            // if the extension is ".xml" then process the xml file
            if (extension == 'xml') {
                var xml = reader.result;
                var sset = $('srcset', xml);

                // Get the set and system ids
                var srcSet = {};
                srcSet.setid = sset.attr("setid");
                srcSet.srclang = sset.attr("srclang");
                srcSet.documents = {};

                var srcDocs = {};
                $('doc', xml).each(function (doc) {
                  var docid = $(this).attr("docid");
                  var segs = [];
                  $(this).find("seg").each(function (seg) {
                    //var segid = $(this).attr("id");
                    segs.push($(this).text().trim());
                    // segs.push(tokenize($(this).text(), $('#caseCheckBox').attr('checked')));
                  });
                  srcSet.documents[docid] = segs;
                });
            }
            else if (extension == "txt") {
                var txt = reader.result;
                var srcSet = {};
                srcSet.setid = "fakeset";
                // Since we don't have the XML to tell us what the source language is, we'll set the
                // source language to 'unknown' for now and then automatically detect it later if
                // we are asked to compare to Bing or Google and have the API key
                srcSet.srclang = "unknown";
                srcSet.documents = {};
                srcSet.untokenizedDocuments = {};
                var docid = "fakedoc";
                var segs = [];
                var originalSegs = txt.split('\n').slice(0, -1);
                for (var i=0; i < originalSegs.length; i++) {
                    segs.push(originalSegs[i].trim());
                }
                srcSet.documents[docid] = segs;
            }
            srcSets.push(srcSet);

            // Enable the Bing/Google radio buttons if the source file has been parsed successfully
            if (srcSets.length > 0) {
                $('input[name=comparisonEngine]').filter('#comparisonEngine1').removeAttr('disabled');
                $('input[name=comparisonEngine]').filter('#comparisonEngine2').removeAttr('disabled');
            }
        }
        reader.readAsText(srcfile);
    });

    // Process the system xml or plaintext file
    // We make the decision based on the extension right now which is a bit hacky
    $('#tstFile').change(function (e) {
        var tstfile = e.target.files[0];
        var reader = new FileReader();
        reader.onload = function() {
            var extension = tstfile.name.split('.').pop();

            // if the extension is ".xml" then process the xml file
            if (extension == 'xml') {
                var xml = reader.result;
                var tset = $('tstset', xml);

                // Get the set and system ids
                var tstSet = {};
                tstSet.setid = tset.attr("setid");
                tstSet.sysid = tset.attr("sysid");
                tstSet.documents = {};
                tstSet.untokenizedDocuments = {};

                $('doc', xml).each(function (doc) {
                    var docid = $(this).attr("docid");
                    var segs = [];
                    var originalSegs = [];
                    $(this).find("seg").each(function (seg) {
                      //var segid = $(this).attr("id");
                      if ($('#tokenizeCheckBox').attr('checked')) {
                        segs.push($(this).text().trim());
                      }
                      else {
                        segs.push(tokenize($(this).text().trim(), $('#caseCheckBox').attr('checked')));
                      }
                      originalSegs.push($(this).text().trim());
                    });
                    tstSet.documents[docid] = segs;
                    tstSet.untokenizedDocuments[docid] = originalSegs;
                });
            }
            else if (extension == "txt") {
                var txt = reader.result;
                var tstSet = {};
                tstSet.setid = "fakeset";
                tstSet.sysid = "fakesys";
                tstSet.documents = {};
                tstSet.untokenizedDocuments = {};
                var docid = "fakedoc";
                var segs = [];
                var originalSegs = txt.split('\n').slice(0, -1);
                for (var i=0; i < originalSegs.length; i++) {
                  if ($('#tokenizeCheckBox').attr('checked')) {
                    segs.push(originalSegs[i].trim());
                  }
                  else {
                    segs.push(tokenize(originalSegs[i].trim(), $('#caseCheckBox').attr('checked')));
                  }
                }
                tstSet.documents[docid] = segs;
                tstSet.untokenizedDocuments[docid] = originalSegs;
            }
            tstSets[0] = tstSet;
        }
        reader.readAsText(tstfile);
        $('#secondHypLink').css('display', 'inline');
    });
    $('#tstFile2').change(function (e) {
        var tstfile = e.target.files[0];
        var reader = new FileReader();
        reader.onload = function() {
            var extension = tstfile.name.split('.').pop();

            if (extension == "xml") {
                var xml = reader.result;
                var tset = $('tstset', xml);

                // Get the set and system ids
                var tstSet = {};
                tstSet.setid = tset.attr("setid");
                tstSet.sysid = tset.attr("sysid");
                tstSet.documents = {};
                tstSet.untokenizedDocuments = {};

                var tstDocs = {};
                $('doc', xml).each(function (doc) {
                    var docid = $(this).attr("docid");
                    var segs = [];
                    var originalSegs = [];
                    $(this).find("seg").each(function (seg) {
                      //var segid = $(this).attr("id");
                      if ($('#tokenizeCheckBox').attr('checked')) {
                        segs.push($(this).text().trim());
                      }
                      else {
                        segs.push(tokenize($(this).text().trim(), $('#caseCheckBox').attr('checked')));
                      }
                      originalSegs.push($(this).text().trim());
                    });
                    tstSet.documents[docid] = segs;
                    tstSet.untokenizedDocuments[docid] = originalSegs;
                });
            }
            else if (extension == "txt") {
                var txt = reader.result;
                var tstSet = {};
                tstSet.setid = "fakeset";
                tstSet.sysid = "fakesys2";
                tstSet.documents = {};
                tstSet.untokenizedDocuments = {};
                var docid = "fakedoc";
                var segs = [];
                var originalSegs = txt.split('\n').slice(0, -1);
                for (var i=0; i < originalSegs.length; i++) {
                  if ($('#tokenizeCheckBox').attr('checked')) {
                    segs.push(originalSegs[i].trim());
                  }
                  else {
                    segs.push(tokenize(originalSegs[i].trim(), $('#caseCheckBox').attr('checked')));
                  }
                }
                tstSet.documents[docid] = segs;
                tstSet.untokenizedDocuments[docid] = originalSegs;
            }
            tstSets[1] = tstSet;
        }
        reader.readAsText(tstfile);
    });

    // Process the system xml or plaintext file
    // We make the decision based on the extension right now which is a bit hacky
    $('#refFile').change(function(e) {
        refSets = [];
        var reffile = e.target.files[0];
        var reader = new FileReader();
        reader.onload = function() {

            var extension = reffile.name.split('.').pop();

            // if the extension is ".xml" then process the xml file
            if (extension == "xml") {
                var xml = reader.result;

                // Process each refset
                $('refset', xml).each(function(refset) {
                    var rset = {};

                    // Get the refid and setid for this refset
                    rset.setid = $(this).attr("setid");
                    rset.refid = $(this).attr("refid");
                    rset.documents = {};
                    rset.untokenizedDocuments = {};

                    // Process all docs in each refset
                    $(this).find("doc").each(function(doc) {
                        var docid = $(this).attr("docid");
                        var segs = [];
                        var originalSegs = [];
                        $(this).find("seg").each(function(seg) {
                          //var segid = $(this).attr("id");
                          if ($('#tokenizeCheckBox').attr('checked')) {
                            segs.push($(this).text().trim());
                          }
                          else {
                            segs.push(tokenize($(this).text().trim(), $('#caseCheckBox').attr('checked')));
                          }
                          originalSegs.push($(this).text().trim());
                        });
                        rset.documents[docid] = segs;
                        rset.untokenizedDocuments[docid] = originalSegs;
                    });
                    refSets.push(rset);
                });
            }
            else if (extension == "txt") {
                var txt = reader.result;
                var rset = {};
                rset.setid = "fakeset";
                rset.refid = "fakeref";
                rset.documents = {};
                rset.untokenizedDocuments = {};
                var docid = "fakedoc";
                var segs = [];
                var originalSegs = txt.split('\n').slice(0, -1);
                for (var i=0; i < originalSegs.length; i++) {
                  if ($('#tokenizeCheckBox').attr('checked')) {
                    segs.push(originalSegs[i].trim());
                  }
                  else {
                    segs.push(tokenize(originalSegs[i].trim(), $('#caseCheckBox').attr('checked')));
                  }
                }
                rset.documents[docid] = segs;
                rset.untokenizedDocuments[docid] = originalSegs;
                refSets.push(rset);
            }
        }
        reader.readAsText(reffile);
    });

    $('a#secondHypLink').click(function(e) {
        e.preventDefault();
        $('#secondHypDiv').slideToggle();
        $(this).css('display', 'none');
    });
    $('#scoreButton').click(function(e) {
        if (tstSets.length > 0 && refSets.length > 0) {

            // validate each test set against the source set, if the latter is present
            if (srcSets.length > 0) {
                for (var i=0; i<tstSets.length; i++) {
                    var tset = tstSets[i];
                    if (tset != undefined) {
                        if (!validateTstAndSrc(tset, srcSets[0])) {
                            alert("Error: the hypothesis file (sysid: " + tset.sysid + ") and the source file do not match up");
                            return false;
                        }
                    }
                }
            }

            // validate each tet set against the reference set
            for (var i=0; i<tstSets.length; i++) {
                var tset = tstSets[i];
                if (tset != undefined) {
                    if (!validateTstAndRefs(tset, refSets)) {
                        alert("Error: the hypothesis file (sysid: " + tset.sysid + ") and one (or more) of the reference files do not match up");
                        return false;
                    }
                }
            }

            // also validate the two test sets against each other
            if (tstSets[1] != undefined) {
                if (!validateTstAndOtherTst(tstSets[0], tstSets[1])) {
                    alert("Error: the hypothesis files do not match up (should have same document IDs, same set IDs but different sys IDs.")
                    return false;
                }
            }

      // clear everything else
      $('#bleuSegPlot').html("");
      $('#bleuDocPlotsContainer').html("");
      $('#bleuDocPlotsContainer').hide();
      $('#bleuSegPlotContainer').hide();
      $('#segDetailContainer').html("");
      allDocPlots = [];

      var scores = [];
      var brevities = [];
      var precisions = [];
      var sysids = [];
      var srclang = srcSets.length > 0 ? srcSets[0].srclang : undefined;

      // Compute the bleu scores for the first system ...
      scontainer = scoreSystem(tstSets[0], refSets);
      for (sysid in scontainer.bleuObjects) {
        var bo = scontainer.bleuObjects[sysid];
          scores.push(bo.computeBLEU());
          brevities.push(bo.brevity);
          precisions.push(bo.precisions[4]);
          sysids.push(sysid);
      }

        // .. and the second system, if available
            if (tstSets[1] != undefined) {
                scontainer2 = scoreSystem(tstSets[1], refSets);
                for (sysid in scontainer2.bleuObjects) {
                    var bo = scontainer2.bleuObjects[sysid];
                    scores.push(bo.computeBLEU());
                    brevities.push(bo.brevity);
                    precisions.push(bo.precisions[4]);
                    sysids.push(sysid);
                }
            }


            // Show BLEU details (with details table hidden) if there is
            // only one system but if there are two, then show the scores
            // side by side and NO table.
            if (tstSets[1] != undefined) {
                showSideBySideScores(scores, precisions, brevities, sysids, srclang, refSets.length);
                $('#bleuTableDiv').html('');
                $('#bleuDetailContainer').css('border', '1px solid');
            }
            else {
                showScore(scores[0], precisions[0], brevities[0], sysids[0], srclang, refSets.length);
                showTable(bo.individualNgramScores, bo.cumulativeNgramScores);
                $('#bleuTable').find('tbody').css('display', 'none');
                $('#bleuDetailContainer').css('border', '1px solid');
            }

            // build the doc plot strip of plots if there is more
            // than one document otherwise we don't need to
            var numDocuments = keys(scontainer.documentScores).length;
            if ( numDocuments > 0) {

                // Set the height and width for the container
                //$('#bleuDocPlotsContainer').css('width', Math.min(700, numDocuments*210));
                $('#bleuDocPlotsContainer').show();
                $('#bleuDocPlotsContainer').css('width', 700);
                $('#bleuDocPlotsContainer').css('height', 150);

                // get data for all doc plots together, either as score differences or raw scores
                // depending on whether there are 1 or 2 systems
                var docPlotArray;
                var ymin, ymax;

                if (tstSets[1] != undefined) {
                    docPlotArray = createDocPlotsDataForComparison(scontainer.documentScores, scontainer.segmentScores, scontainer2.documentScores, scontainer2.segmentScores);
                  ymax = findSymmetricYAxisLimits(docPlotArray[0]);
                  ymin = -ymax;
                }
                else {
                    docPlotArray = createDocPlotsData(scontainer.documentScores, scontainer.segmentScores);
                  ymin = 0.0;
                  ymax = 1.0;
                }
                var docPlotScores = docPlotArray[0];
                var docPlotTicks = docPlotArray[1];
                var docPlotLabels = docPlotArray[2];

                var seriesLabel;
                var plotLabel;
                        var idLabel;

                // Make all the document plots
                for (var i=0; i < numDocuments; i++) {

                        // Create a label for the plot
                        idLabel = ("00" + i).slice(-3); // pad with two leading zeros

                    // render the plot placeholder
                    $('#bleuDocPlotsContainer').append('<div class="docplot" id="docPlot' + idLabel + '" style="width:200px; height:100px; display:inline-block; margin: 10px; white-space:nowrap;"</div>');

                    // render the plot itself
                    seriesLabel = 'DocID: ' + docPlotLabels[i][0] + ' (' + docPlotLabels[i][1] + ')';
                    plot = makeColumnChart('docPlot' + idLabel, docPlotScores[i], docPlotTicks[i], seriesLabel, "small", ymin, ymax);

                    // save a reference to the plot
                    //allDocPlots.push(plot);

                    // Create a non-legend label for the plot
                    plotLabel = 'Document ' + (i+1) + ' (' + docPlotLabels[i][1] + ')';
                        idLabel = ("00" + i).slice(-3); // pad with two leading zeros
                    $('#docPlot' + idLabel).append('<span id="docPlotLabel' + i + '" style="font-size: 11px; margin: 0px auto;">' + plotLabel + '</span>');
                }
            }
        }
        else {
            alert('Please load both the hypothesis and reference files.');
        }
    });
    $('#caseCheckBox').click(function(e) {

        // Store the previous state of the compare link
        var prevLinkValue = $('a#secondHypLink').css('display');

        if (tstSets.length > 0) {
            $('#tstFile').trigger('change');

            if (tstSets[1] != undefined) {
                $('#tstFile2').trigger('change');
            }

            // Make sure that the compare link retains its state
            $('a#secondHypLink').css('display', prevLinkValue);
        }
        if (refSets.length > 0) {
            $('#refFile').trigger('change');
        }
    });
    $('#tokenizeCheckBox').click(function(e) {

        // Store the previous state of the compare link
        var prevLinkValue = $('a#secondHypLink').css('display');

        if (tstSets.length > 0) {
            $('#tstFile').trigger('change');

            if (tstSets[1] != undefined) {
                $('#tstFile2').trigger('change');
            }

            // Make sure that the compare link retains its state
            $('a#secondHypLink').css('display', prevLinkValue);
        }
        if (refSets.length > 0) {
            $('#refFile').trigger('change');
        }
    });
    $('a#formHider').click(function(e) {
        e.preventDefault();
        $('#fileForm').slideToggle();
        if ($(this).html() == 'Hide Form') {
            $(this).html('Show Form');
        }
        else {
            $(this).html('Hide Form');
        }
    });
    $('a#tableHider').live('click', function(e) {
        e.preventDefault();
        $('#bleuTable').find('tbody').toggle();
        if ($(this).html() == 'Show') {
            $(this).html('Hide');
        }
        else {
            $(this).html('Show');
        }
    });

      $('a#engineTranslate').live('click', function(e) {
        e.preventDefault();
        var engineName = $('input[name=comparisonEngine]:checked').val();
        if (engineName == "Google") {
            if (!window.google_translate_api_key) {
                var key = prompt('Please enter your Google Translate API Key which can be freely obtained from Google. It will only be saved for this session. If you wish to permanently save this key, please edit this HTML file directly.');
                if (key) { window.google_translate_api_key = key; }
                else { return false; }
            }
        }
        else {
            if (!window.bing_translate_api_key) {
                var key = prompt('Please enter your Bing Translate API Key which can be freely obtained from Microsoft. It will only be saved for this session. If you wish to permanently save this key, please edit this HTML file directly.');
                if (key) { window.bing_translate_api_key = key; }
                else { return false; }
            }
        }
        var segdocdata = $('td#segDetailID').html().match(docidpat2);
        var segnum = parseInt(segdocdata[1])-1;
        var docid = segdocdata[2];
        $('tr#segDetailEngine').html('<td colspan="2" style="text-align: center; font-size: 14px;">Translating ...</td>')
        if (engineName == "Google") {
          googleTranslate(srcSets[0].documents[docid][segnum]);
        }
        else {
            bingTranslate(srcSets[0].documents[docid][segnum], srcSets[0].srclang);
        }
        $('html, body').animate({
            scrollTop: $("tr#segDetailEngine").offset().top
        }, 1000);
    });
});
</script>
</html>
